之前我们使用的都是TF卡启动,对应的硬件接口是SD0。现在要更改启动方式,从eMMC启动系统,就要在之前的配置上做一些更改:
在vivado的block design中需使能SD1(eMMC在核心板上挂载在SD1接口上):
继续后续的操作:“Generate Bitstream"-->Export Hardware"--->导出.xsa文件。
将.xsa文件通过共享文件夹从Windows拷贝到虚拟机上,再将共享文件夹里的xsa文件复制到工作目录里:
在工作目录里运行petalinux环境,进行相关配置:使用命令:
xspetapetalinux-config --get-hw-description=.#导入新的xsa并完成配置
将uboot配置到qspi-flash,image和rootfs都配置到eMMC中:
对qspi-flash进行分区:
xxxxxxxxxxpetalinux-config --get-hw-description=.Subsystem AUTO Hardware Settings-->Flash Settings-->文件系统在mmcblk1p2,对应emmc的第二个分区
xxxxxxxxxxpetalinux-config --get-hw-description=.Image Packaging Configuration--->选择ps7_sd_1. ps7_sd_1对应eMMC
xxxxxxxxxxpetalinux-config --get-hw-description=.Subsystem AUTO Hardware Settings-->SD/SDIO Settings-->
xxxxxxxxxxpetalinux-config --get-hw-description=.petalinux-config -> u-boot configuration ->u-boot script configuration -> QSPI/SPI image offsets# 这里zynq使用的是image.ub(里面包含kernel和dtb, image.ub属于fit image)xxxxxxxxxxpetalinux-config -c u-boot ARM architecture -> (0xFE0000) Boot script offset# 0xFE0000 对应qspi flash中的bootsrc的起始地址编译并打包
xxxxxxxxxxpetalinux-buildpetalinux-package --boot --fsbl ./images/linux/zynq_fsbl.elf --u-boot --fpga --force#至此生成boot.src/BOOT.bin/image.ub/roofs.tar.gz先将开发板配置成SD卡启动模式,接上网线,上电启动后,在其/home/root目录下创建image文件夹。然后通过ftp的方式,把虚拟机上生成的image.ub、roofs.tar.gz拷贝到image下。至此eMMC模式下的内核镜像和文件系统都已经临时保存在TF卡上了。
将产生BOOT.bin/image.ub/zynq_fsbl.elf/boot.src文件拷贝到windows环境下。将开发板设置成JTAG模式,上电后通过vitis的program flash工具将BOOT.bin/image.ub/zynq_fsbl.elf/boot.src文件烧写到qspi-flash中(具体烧入的地址参考前面的qspi-flash的分区信息):
(1)烧写BOOT.bin:image file选择BOOT.bin,offset填0x0000000
(2)烧写image.ub:先把image.ub改名成image.ub.bin;然后image file选择image.ub.bin,offeset填0x5A0000
(3)烧写boot.src:先把boot.src改名成boot.src.bin;然后image file选择boot.src.bin,offeset填0xFE0000:
uboot启动后,会去加载boot.src脚本,在该脚本中会根据当前的启动模式,进行相应的读取和加载以及bootm。
对eMMC格式化并分区
断电后,将启动模式设置为SD卡,并将TF卡插入卡槽,上电后进入到TF卡中的linux系统。
删除emmc原有分区并重新分区
xxxxxxxxxx# 查看emmc当前的分区是否有挂载点mount# 如果有挂载,则先umountumount /dev/mmcblk1p1umount /dev/mmcblk1p2# 格式化emmc#fdisk /dev/mmcblk1删除分区
输入“p”,会看到当前分区情况。
输入"d",将一个分区删除,如果有多个分区,则需要输入多次d。
再输入“p”,会看到当前分区情况。
创建第一个分区
输入“n”,将创建一个分区。输入“p”(primary partition),然后依次输入“1”(partiton number)、“2048”(first sector)、“+1G”(第一个分区分配1GB)或者直接指定last sector。
输入“t”,设置分区类型,输入“b”,将类型设置为“W95 FAT32”。
再输入“p”,会看到当前分区情况,包括当前该分区的结束扇区号(对应EndLBA)。
创建第二个分区
使用“n”命令,输入“p”(primary partition),然后依次输入“2”、将剩余空间都留给第二个分区,直接回车就可以了。
如果创建第二个分区时,first sector没有在第一个分区的结束扇区号的基础上自己增加的话,则输入前一个分区的EndLBA值+1。
检查分区表
输入“p”,检查一下是不是两个分区;都没问题则输入“w”,将分区表写入tf卡。
格式化分区表
xxxxxxxxxx# 将第一个分区格式化为FAT32mkfs.vfat -F 32 /dev/mmcblk1p1# 将第二个分区格式化为EXT4mkfs.ext4 /dev/mmcblk1p2 将TF中保存的emmc启动用的image.ub和roofs.tar.gz拷贝和解压到emmc的分区中
xxxxxxxxxx# 创建两个文件夹作为emmc两个分区的挂载点mkdir /media/mmcblk1p1mkdir /media/mmcblk1p2# 将/dev/mmcblk1p1挂载到/media/mmcblk1p1mount /dev/mmcblk1p1 /media/mmcblk1p1# 将/dev/mmcblk1p2挂载到/mnt/mmcblk1p2mount /dev/mmcblk1p2 /media/mmcblk1p2# image.ub拷贝到/dev/mmcblk1p1cp /home/root/image/image.ub /media/mmcblk1p1sync
# rootfs.tar.gz解压到/dev/mmcblk1p2tar -xzf /home/root/image/rootfs.tar.gz -C /media/mmcblk1p2sync注:因为image是从qspi-flash中加载,所以image.ub不拷贝到第一个分区也可以。
断电后,将启动模式设置为spi-flash模式,并上电。这时uboot和内核会从qspi-flash加载,文件系统会从eMMC加载。
uboot启动后,会去加载boot.src脚本,在该脚本中会根据当前的启动模式,进行相应的读取和加载以及bootm。
以下是默认的boot.src文件的内容
xxxxxxxxxx# 遍历boot模式(JTAG/QSPI/MMC/NAND)for boot_target in ${boot_targets};do echo "Trying to load boot images from ${boot_target}" if test "${boot_target}" = "jtag" ; then bootm 0x00200000 0x04000000 0x00100000 fi if test "${boot_target}" = "mmc0" || test "${boot_target}" = "mmc1" ; then # 如果从mmc启动,则判断mmc下是否有uEnv.txt文件(目前的petalinux不会包含该文件) if test -e ${devtype} ${devnum}:${distro_bootpart} /uEnv.txt; then # 加载uEnv.txt文件 fatload ${devtype} ${devnum}:${distro_bootpart} 0x02080000 uEnv.txt; echo "Importing environment(uEnv.txt) from ${boot_target}..." env import -t 0x02080000 $filesize if test -n $uenvcmd; then echo "Running uenvcmd ..."; run uenvcmd; fi fi # 如果mmc包含image.ub文件 if test -e ${devtype} ${devnum}:${distro_bootpart} /image.ub; then # 加载image.ub文件到0x10000000 fatload ${devtype} ${devnum}:${distro_bootpart} 0x10000000 image.ub; # 从0x10000000启动 bootm 0x10000000; fi # 如果从mmc启动,则正常情况下,以下代码不会执行到 # 如果mmc包含uImage文件和system.dtb文件 if test -e ${devtype} ${devnum}:${distro_bootpart} /uImage; then fatload ${devtype} ${devnum}:${distro_bootpart} 0x00200000 uImage;; fi if test -e ${devtype} ${devnum}:${distro_bootpart} /system.dtb; then fatload ${devtype} ${devnum}:${distro_bootpart} 0x00100000 system.dtb; fi # 如果mmc包含ramdisk.cpio.gz.u-boot文件 if test -e ${devtype} ${devnum}:${distro_bootpart} /ramdisk.cpio.gz.u-boot && test "${skip_tinyramdisk}" != "yes"; then fatload ${devtype} ${devnum}:${distro_bootpart} 0x04000000 ramdisk.cpio.gz.u-boot; bootm 0x00200000 0x04000000 0x00100000 fi if test -e ${devtype} ${devnum}:${distro_bootpart} /rootfs.cpio.gz.u-boot && test "${skip_ramdisk}" != "yes"; then fatload ${devtype} ${devnum}:${distro_bootpart} 0x04000000 rootfs.cpio.gz.u-boot; bootm 0x00200000 0x04000000 0x00100000 fi bootm 0x00200000 - 0x00100000 fi # 如果从qspi启动 if test "${boot_target}" = "xspi0" || test "${boot_target}" = "qspi" || test "${boot_target}" = "qspi0"; then sf probe 0 0 0; # 将qspi偏移地址0x5A0000,长度0xA40000的内容加载到0x10000000 # 0x5A0000和0xA40000对应前面qspi的空间划分的image.ub sf read 0x10000000 0x5A0000 0xA40000 # 从0x10000000启动 bootm 0x10000000; echo "Booting using Fit image failed"
sf read 0x00200000 0x1000000 0x500000 sf read 0x04000000 0x1580000 0xA00000 bootm 0x00200000 0x04000000 0x00100000; echo "Booting using Separate images failed" fi if test "${boot_target}" = "nand" || test "${boot_target}" = "nand0"; then nand info; nand read 0x10000000 0x1080000 0x6400000 bootm 0x10000000; echo "Booting using Fit image failed"
nand read 0x00200000 0x1000000 0x3200000 nand read 0x04000000 0x4600000 0x3200000 bootm 0x00200000 0x04000000 0x00100000; echo "Booting using Separate images failed" fidone如果boot mode是qspi,那么uboot和image都会从qspi flash加载。
如果boot mode是mmc0或者mmc1,则uboot和image都会从mmc加载。
根据前面对boot.src文件的分析,如果想从qspi flash加载uboot,从mmc加载image,那么就需要修改boot.src文件。
因为boot.src文件本身是带crc校验的,所以直接修改boot.src内容,会导致boot.src校验失败,从而无法启动内核。
boot.src是通过components/yocto/layers/meta-xilinx/meta-xilinx-bsp/recipes-bsp/u-boot/u-boot-zynq-scr/boot.cmd.generic为模板而生成的,所以可以修改boot.cmd.generic文件。
但是boot.cmd.generic文件在petalinux-config时可能会被自动覆盖。
合理的修改办法是通过在project-spec/meta-user/recipes-bsp/uboot/的增加一个u-boot-zynq-scr.bbappend和一个u-boot-zynq-scr文件夹来解决。
Patching U-Boot boot script in Petalinux 2021.1
qspi-falsh可以还是按照上述步骤进行空间划分;包括petalinux-config和uboot config;
在project-spec/meta-user/recipes-bsp/uboot/下创建u-boot-zynq-scr.bbappend文件和u-boot-zynq-scr文件夹
xxxxxxxxxx# u-boot-zynq-scr.bbappend文件内容如下:
FILESEXTRAPATHS_prepend := "${THISDIR}/u-boot-zynq-scr:"
SRC_URI += "file://boot.cmd.generic"将components/yocto/layers/meta-xilinx/meta-xilinx-bsp/recipes-bsp/u-boot/u-boot-zynq-scr/boot.cmd.generic文件拷贝到u-boot-zynq-scr文件夹下,然后修改该文件:
xxxxxxxxxx# This is a boot script for U-Boot# Generate boot.scr:# mkimage -c none -A arm -T script -d boot.cmd.default boot.scr#################@@PRE_BOOTENV@@
for boot_target in ${boot_targets};do echo "Trying to load boot images from ${boot_target}" if test "${boot_target}" = "jtag" ; then @@KERNEL_BOOTCMD@@ @@KERNEL_LOAD_ADDRESS@@ @@RAMDISK_IMAGE_ADDRESS@@ @@DEVICETREE_ADDRESS@@ fi if test "${boot_target}" = "mmc0" || test "${boot_target}" = "mmc1" ; then if test -e ${devtype} ${devnum}:${distro_bootpart} /@@UENV_TEXTFILE@@; then fatload ${devtype} ${devnum}:${distro_bootpart} @@UENV_MMC_LOAD_ADDRESS@@ @@UENV_TEXTFILE@@; echo "Importing environment(@@UENV_TEXTFILE@@) from ${boot_target}..." env import -t @@UENV_MMC_LOAD_ADDRESS@@ $filesize if test -n $uenvcmd; then echo "Running uenvcmd ..."; run uenvcmd; fi fi if test -e ${devtype} ${devnum}:${distro_bootpart} /@@FIT_IMAGE@@; then fatload ${devtype} ${devnum}:${distro_bootpart} @@FIT_IMAGE_LOAD_ADDRESS@@ @@FIT_IMAGE@@; bootm @@FIT_IMAGE_LOAD_ADDRESS@@; fi if test -e ${devtype} ${devnum}:${distro_bootpart} /@@KERNEL_IMAGE@@; then fatload ${devtype} ${devnum}:${distro_bootpart} @@KERNEL_LOAD_ADDRESS@@ @@KERNEL_IMAGE@@;; fi if test -e ${devtype} ${devnum}:${distro_bootpart} /system.dtb; then fatload ${devtype} ${devnum}:${distro_bootpart} @@DEVICETREE_ADDRESS@@ system.dtb; fi if test -e ${devtype} ${devnum}:${distro_bootpart} /@@RAMDISK_IMAGE1@@ && test "${skip_tinyramdisk}" != "yes"; then fatload ${devtype} ${devnum}:${distro_bootpart} @@RAMDISK_IMAGE_ADDRESS@@ @@RAMDISK_IMAGE1@@; @@KERNEL_BOOTCMD@@ @@KERNEL_LOAD_ADDRESS@@ @@RAMDISK_IMAGE_ADDRESS@@ @@DEVICETREE_ADDRESS@@ fi if test -e ${devtype} ${devnum}:${distro_bootpart} /@@RAMDISK_IMAGE@@ && test "${skip_ramdisk}" != "yes"; then fatload ${devtype} ${devnum}:${distro_bootpart} @@RAMDISK_IMAGE_ADDRESS@@ @@RAMDISK_IMAGE@@; @@KERNEL_BOOTCMD@@ @@KERNEL_LOAD_ADDRESS@@ @@RAMDISK_IMAGE_ADDRESS@@ @@DEVICETREE_ADDRESS@@ fi @@KERNEL_BOOTCMD@@ @@KERNEL_LOAD_ADDRESS@@ - @@DEVICETREE_ADDRESS@@ fi if test "${boot_target}" = "xspi0" || test "${boot_target}" = "qspi" || test "${boot_target}" = "qspi0"; then ### 这个if是增加的部分 ### 判断mmc 1:${distro_bootpart}上是否有image.ub文件 ### 即eMMC第一个分区是否有image.ub文件 if test -e mmc 1:${distro_bootpart} /@@FIT_IMAGE@@; then echo "try to boot using mmc1 Fit image" # 如果有,则加载到FIT_IMAGE_LOAD_ADDRESS地址(对应的是0x1000000) fatload mmc 1:${distro_bootpart} @@FIT_IMAGE_LOAD_ADDRESS@@ @@FIT_IMAGE@@; # 从FIT_IMAGE_LOAD_ADDRESS地址启动 bootm @@FIT_IMAGE_LOAD_ADDRESS@@; echo "Booting using mmc1 Fit image failed" fi # 如果mmc上没有image.ub文件,则还是会从qspi上加载image.ub echo "try to boot using qspi Fit image" sf probe 0 0 0; sf read @@FIT_IMAGE_LOAD_ADDRESS@@ @@QSPI_FIT_IMAGE_OFFSET@@ @@QSPI_FIT_IMAGE_SIZE@@ bootm @@FIT_IMAGE_LOAD_ADDRESS@@; echo "Booting using Fit image failed"
sf read @@KERNEL_LOAD_ADDRESS@@ @@QSPI_KERNEL_OFFSET@@ @@QSPI_KERNEL_SIZE@@ sf read @@RAMDISK_IMAGE_ADDRESS@@ @@QSPI_RAMDISK_OFFSET@@ @@QSPI_RAMDISK_SIZE@@ @@KERNEL_BOOTCMD@@ @@KERNEL_LOAD_ADDRESS@@ @@RAMDISK_IMAGE_ADDRESS@@ @@DEVICETREE_ADDRESS@@; echo "Booting using Separate images failed" fi if test "${boot_target}" = "nand" || test "${boot_target}" = "nand0"; then nand info; nand read @@FIT_IMAGE_LOAD_ADDRESS@@ @@NAND_FIT_IMAGE_OFFSET@@ @@NAND_FIT_IMAGE_SIZE@@ bootm @@FIT_IMAGE_LOAD_ADDRESS@@; echo "Booting using Fit image failed"
nand read @@KERNEL_LOAD_ADDRESS@@ @@NAND_KERNEL_OFFSET@@ @@NAND_KERNEL_SIZE@@ nand read @@RAMDISK_IMAGE_ADDRESS@@ @@NAND_RAMDISK_OFFSET@@ @@NAND_RAMDISK_SIZE@@ @@KERNEL_BOOTCMD@@ @@KERNEL_LOAD_ADDRESS@@ @@RAMDISK_IMAGE_ADDRESS@@ @@DEVICETREE_ADDRESS@@; echo "Booting using Separate images failed" fidone按照之前的步骤:petalinux-build以及打包后,将BOOT.bin、boot.src、image.ub、zynq_fsbl.elf拷贝到windows下,使用vitis烧入qspi-flash即可;image.ub文件拷贝eMMC的第一个分区,rootfs解压到eMMC的第二个分区即可。